﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace AircraftBattleServer
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "GameEngineService" in both code and config file together.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class GameEngineService : IGameEngineService
    {
        public static MapData mapdata = new MapData();
        private static AircraftBattleDB.BattleDB db = new AircraftBattleDB.BattleDB();
        public static bool gameStarted = false;

        public GameEngineService()
        {

        }

        #region IGameEngineService Members

        // in order to move in client side seprately, the client may need to get the stepsize
        // so I define this interface
        // by Pengfei

        public double GetConstant(int choice)
        {
            switch(choice)
            {
                case 1:
                   return Constants.MovementOneStepLength;
                case 2:
                    return Constants.MissileDefaultSpeed;
                default:
                    return 0;
            }
        }

        public void SetPosition(int craftId, double left, double top)
        {
            if (!gameStarted) return;

            if (craftId < 0)
            {
                throw new Exception("Craft id can not be negative value");
            }

            lock (mapdata)
            {
                try
                {
                    mapdata.GetAircraft(craftId).position.x = left;
                    mapdata.GetAircraft(craftId).position.y = top;
                }
                catch (Exception ex)
                {
                    throw new Exception("Set position failed, probably because id does not exist", ex); 
                }
            }
        }

        public MyPoint GetPosition(int id)
        {
            try
            {
                return mapdata.GetAircraft(id).position;
            }
            catch (Exception ex)
            {
                throw new Exception("The given aircraft id does not exist", ex);
            }
        }

        public void AddMissile(string id, double x, double y, double angle)
        {
            lock (mapdata)
            {
                mapdata.missiles.Add(new Missile(id, new MyPoint(x, y), angle));
            }
        }

        public MapData GetMapData()
        {
            return mapdata;
        }

        public bool IfUserExist(string username)
        {
            return db.IfUserExist(username);
        }

        public bool IsAdmin(string username)
        {
            return db.IsAdmin(username);
        }

        public string CreateUser(string username)
        {
            try
            {
                db.CreateUser(username);
            }
            catch (Exception e)
            {
                return e.Message;
            }

            return "success";
        }

        public string GetPassword(string username)
        {
            return db.GetPassword(username);
        }

        public int GetAircraftID(string username)
        {
            return db.GetAircarftID(username);
        }

        public void SetAngle(int craftId, double angle)
        {
            if (!gameStarted) return;

            if (craftId < 0)
            {
                throw new Exception("Craft id cannot be negative value");
            }

            lock (mapdata)
            {
                try {
                    mapdata.GetAircraft(craftId).angle = angle;
                }
                catch (Exception ex)
                {
                    throw new Exception("SetAngle failed, probably because id does not exist", ex);
                }
            }
        }

        public void AddPlayer(string username, int craftID)
        {
            lock(mapdata)
            {
                mapdata.userList.Add(new User(username, craftID));
                mapdata.aircrafts.Add(craftID, new Aircraft(craftID, new MyPoint (100, 100), Constants.AircraftInitialAngle1));
            }
        }

        public void SetTeam(string username, int team)
        {
            lock (mapdata)
            {
                mapdata.userList.Find(
                    delegate(User u)
                    {
                        return u.userName == username;
                    }
                    ).SetTeam(team);
            }
        }

        public void SetReady(string username, int ready)
        {
            lock (mapdata)
            {
                mapdata.userList.Find(
                    delegate(User u)
                    {
                        return u.userName == username;
                    }
                    ).SetReady(ready);
            }
        }

        public void AddAircraft(int id, MyPoint p, double angle)
        {
            if (p == null)
                p = new MyPoint(400, 400);

            if (id < 0)
                throw new Exception("Id can't be negative");

            if (id == 0)
                throw new Exception("Id can't be zero");

            p.x = (p.x > 800) ? 800 : p.x;
            p.x = (p.x < 0) ? 0 : p.x;
            p.y = (p.y > 600) ? 600 : p.y;
            p.y = (p.y < 0) ? 0 : p.y;


            lock (mapdata)
            {
                mapdata.aircrafts.Add(id, new Aircraft(id, p, angle));
            }
        }

        public void DeletePlayer(string username, int craftID)
        {
            lock (mapdata)
            {
                mapdata.userList.Remove(
                    mapdata.userList.Find(
                    delegate(User u)
                    {
                        return u.userName == username;
                    }
                    ));

                this.RemoveAircraft(craftID);
            }
        }

        public void InitializePosition()
        {
            int team1Xaxis = 50;
            int team2Xaxis = 700;

            lock (mapdata)
            {
                foreach (User u in mapdata.userList)
                {
                    if (u.team == 1)
                    {
                        mapdata.GetAircraft(u.craftID).position = new MyPoint(team1Xaxis, 500);
                        team1Xaxis += 100;
                    }
                    else
                    {
                        mapdata.GetAircraft(u.craftID).position = new MyPoint(team2Xaxis, 50);
                        team2Xaxis -= 100;
                    }
                }
            }
        }

        public void RemoveAircraft(int id)
        {
            lock (mapdata)
            {
                if (mapdata.aircrafts.ContainsKey(id)) mapdata.aircrafts.Remove(id);
                else throw new Exception("Id does not exist.");
            }
        }

        public int GetWinRecord(string username)
        {
            return db.GetWinRecord(username);
        }

        public int GetLoseRecord(string username)
        {
            return db.GetLoseRecord(username);
        }

        public void StartGame()
        {
            gameStarted = true;
            mapdata.winer = 0;
        }

        public void AddWinRecord(string username)
        {
            db.AddWinRecord(username);
        }

        public void AddLoseRecord(string username)
        {
            db.AddLoseRecord(username);
        }

        public void AddKillRecord(string username)
        {
            db.AddKillRecord(username);
        }

        public bool GetBlockInfo(string username)
        {
            return db.GetBlockInfo(username);
        }

        public void SetBlockInfo(string username, bool blocked, string commander, string password)
        {
            bool judge1 = IsAdmin(commander);
            bool judge2 = (this.GetPassword(commander) == password) ? true : false;
            if (judge1 & judge2)
            {
            db.SetBlockInfo(username, blocked);
            }
        }

        public int GetMaxUserID()
        {
            return db.GetMaxUserID();
        }

        public string GetUserName(int id)
        {
            return db.GetUserName(id);
        }

        #endregion
    }
}
